'''
Author: Ryan
Email: 409266255@qq.com
Date: 2025-09-23 14:49:58

LastEditors: Ryan
LastEditTime: 2025-09-30 10:52:12
Description: Akshare数据源

PS：港美股接口
- stock_hk_spot_em， 实时行情数据-东财
    - 不稳定，接口限流
- stock_hk_main_board_spot_em，港股主板实时行情数据-东财
    - 不稳定，接口限流
- stock_hk_spot， 实时行情数据-新浪
    - 用于获取港股列表，不包含8开头的数据
- stock_hk_hist，历史行情数据-东财
- stock_hk_daily，历史行情数据-新浪
    - 后复权，适合回测


FilePath: /qopilot/qopilot/data/datasource/qop_akshare.py
Copyright (c) 2025 by Ryan, All Rights Reserved. 
'''

import akshare as ak
import pandas as pd
from datetime import datetime as dt
import logging

from qopilot.constant import Adjust, TradeDate, Frequency
from qopilot.utils import standardize_column_names

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 股票列表字段 - 新浪财经
stocks_list_config_sina = {
    'rename': {
        '代码': 'code', 
        '中文名称': 'name', 
        '英文名称': 'name_en', 
        '日期时间': 'date', 
        '交易类型': 'trade_type', 
        '今开': 'open', 
        '最新价': 'close', 
        '最高': 'high', 
        '最低': 'low', 
        '成交量': 'volume', 
        '成交额': 'amount', 
        '涨跌幅': 'pct_change', 
        '涨跌额': 'change', 
        '昨收': 'pre_close', 
        '买一': 'buy_1', 
        '卖一': 'sell_1', 
    },
    'keep': ['code', 'name', 'date'],
    'drop': []
}

# 股票历史行情数据字段 - 东方财富
stocks_hist_config_eastmoney = {
    'rename': {
        '日期': 'date',             # 日期
        '开盘': 'open',             # 开盘
        '收盘': 'close',            # 收盘
        '最高': 'high',             # 最高
        '最低': 'low',              # 最低
        '成交量': 'volume',         # 成交量
        '成交额': 'amount',         # 成交额
        '振幅': 'amplitude',        # 振幅
        '涨跌幅': 'pct_change',     # 涨跌幅
        '涨跌额': 'change',         # 涨跌额
        '换手率': 'turnover_rate',  # 换手率
    },
    'keep': [],
    'drop': ['amplitude', 'change', 'turnover_rate']
}


class HKAKShareData():
    """港股EFinance数据获取类"""

    def __init__(self):
        logger.info("港股数据获取器初始化成功")

    def get_hk_stocks_list(self) -> pd.DataFrame:
        """
        获取港股列表

        Returns:
            DataFrame: 港股列表数据（已过滤掉ts_code以'8'开头的数据）

        Api Ref:
            https://tushare.pro/document/2?doc_id=191
        """
        try:
            logger.info("开始获取港股列表")

            # 调用AKShare接口 - 「新浪」实时行情数据，东财接口经常会限流
            df = ak.stock_hk_spot()

            # 列重命名，并过滤掉code以'8'开头的数据
            df_standardized = standardize_column_names(df, stocks_list_config_sina)

            df_standardized['date'] = pd.to_datetime(df_standardized['date']).dt.strftime('%Y%m%d')

            if not df_standardized.empty and 'code' in df_standardized.columns:
                df_standardized = df_standardized[~df_standardized['code'].str.startswith('8')]
            else:
                logger.info("数据为空或缺少code字段，无需过滤")

            logger.info(f"成功获取港股列表，共{len(df_standardized)}条记录")

            return df_standardized

        except Exception as e:
            logger.error(f"获取港股列表失败: {str(e)}")
            raise

    def get_hk_hist(self, 
                    code: str,
                    period: str = Frequency.DAILY.value,
                    start_date: str = TradeDate.START_DATE.value,
                    end_date: str = None,
                    adjust: str = Adjust.QFQ.value) -> pd.DataFrame:
        """
        获取港股历史行情数据

        Args:
            code: 股票代码
            period: 周期，默认为'daily'，可选为'daily', 'weekly', 'monthly'
            start_date: 开始日期，默认为'20100101'
            end_date: 结束日期，默认为'20250928'
            adjust: 调整方式，默认为'hfq'，可选为'hfq', 'qfq', 'none'

        Returns:
            DataFrame: 港股历史行情数据

        Api Ref:
            https://akshare.readthedocs.io/zh_CN/latest/data/stock/stock.html#akshare.stock.hk_hist
        """
        try:
            logger.info("开始获取港股历史行情数据")

            if end_date is None:
                end_date = dt.now().strftime('%Y%m%d')

            # 获取历史行情数据
            df = ak.stock_hk_hist(symbol=code, period=period, start_date=start_date, end_date=end_date, adjust=adjust)

            # 列重命名，并过滤掉一些列
            df_standardized = standardize_column_names(df, stocks_hist_config_eastmoney)
            df_standardized['date'] = pd.to_datetime(df_standardized['date']).dt.strftime('%Y%m%d')

            # 将数据写入Excel文件
            # excel_filename = f"{code}.hk_{adjust}_hist_{pd.Timestamp.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
            # write_to_excel(df_standardized, excel_filename)

            logger.info(f"成功获取港股历史行情数据，股票代码: {code}，共{len(df_standardized)}条记录")
            return df_standardized

        except Exception as e:
            logger.error(f"获取港股历史行情数据失败: {str(e)}")
            raise

    def get_hk_hist_batch(self, 
                          codes: list, 
                          period: str = Frequency.DAILY.value, 
                          start_date: str = TradeDate.START_DATE.value, 
                          end_date: str = None, 
                          adjust: str = Adjust.QFQ.value):
        """
        批量获取港股历史行情数据

        Args:
            codes: 股票代码列表
            period: 周期，默认为'daily'，可选为'daily', 'weekly', 'monthly'
            start_date: 开始日期，默认为'20100101'
            end_date: 结束日期，默认为'20250928'
            adjust: 调整方式，默认为'hfq'，可选为'hfq', 'qfq', 'none'
        """
        try:
            logger.info("开始批量获取港股历史行情数据")

            if end_date is None:
                end_date = dt.now().strftime('%Y%m%d')

            for code in codes:
                df = self.get_hk_hist(code, period, start_date, end_date, adjust)
                # df_standardized = standardize_column_names(df, history_column_config_sina)
                # df_standardized.to_excel(excel_path, index=False, engine='openpyxl')
                # logger.info(f"港股历史行情数据已导出到Excel文件: {excel_path}")
                print(df.head(1))

            logger.info(f"成功批量获取港股历史行情数据，共{len(codes)}家记录")

        except Exception as e:
            logger.error(f"批量获取港股历史行情数据失败: {str(e)}")
            raise

    def get_hk_realtime_adj(self,
                            code: str,
                            start_date: str = TradeDate.START_DATE.value,
                            end_date: str = dt.now().strftime('%Y%m%d')) -> pd.DataFrame:
        """
        获取港股实时复权行情数据
        """
        try:
            logger.info("开始获取港股实时复权行情数据")
            df = ak.stock_hk_realtime_adj(code, start_date, end_date)
            print(df.head(1))
            return df
        except Exception as e:
            logger.error(f"获取港股实时复权行情数据失败: {str(e)}")
            raise


class USAKShareData():
    """美股EFinance数据获取类"""

    def __init__(self):
        logger.info("美股数据获取器初始化成功")


def test():
    hk = HKAKShareData()
    # df = hk.get_hk_stocks_list()
    # print(df)
    df = hk.get_hk_hist(code='00700', 
                        period=Frequency.DAILY.value, 
                        start_date='20250101', 
                        end_date='20250928', 
                        adjust=Adjust.QFQ.value)
    print(df)
    # hk.get_hk_hist_batch(codes=['00700'], start_date='19000101', adjust='hfq')


if __name__ == "__main__":
    test()
